use crate::hardware::Interposer;
use crate::hardware::{COBDirection, COBCoord};

use super::{COB_SEL_REGEX, COB_SW_REGEX};

use std::error::Error;
use std::path::Path;
use std::io::Write;
use std::str::FromStr;

pub fn wirte_controlbits<P1, P2>(
    interposer: &Interposer,
    origin_file_paths: &[P1],
    output_folder: P2,
) -> Result<(), Box<dyn Error>>
where
    P1: AsRef<Path>,
    P2: AsRef<Path>,
{
    let output_folder = output_folder.as_ref();
    // Create output_folder is neccess
    std::fs::create_dir(output_folder)?;

    for path in origin_file_paths {
        // Get input file name(Not path!)
        let input_path = path.as_ref();
        let file_name = input_path.file_name().ok_or(format!("'{}' is not a file path!", input_path.display()))?;
        let output_path = output_folder.join(file_name);

        let content = std::fs::read_to_string(path)?;
        let mut outfile = std::fs::File::create(output_path)?;

        for line in content.lines() {
            let new_line = if let Some(captures) = COB_SW_REGEX.captures(line) {
                let address = &captures[2];
                let row = captures[3].parse::<i64>().unwrap();
                let col = captures[4].parse::<i64>().unwrap();
                let dir = &captures[5];
                let group = captures[6].parse::<usize>().unwrap();

                let (from_dir, to_dir) = match dir {
                    "ru" => (COBDirection::Right, COBDirection::Up),
                    "lu" => (COBDirection::Left, COBDirection::Up),
                    "rd" => (COBDirection::Right, COBDirection::Down),
                    "ld" => (COBDirection::Left, COBDirection::Down),
                    "h" => (COBDirection::Left, COBDirection::Right),
                    "v" => (COBDirection::Up, COBDirection::Down),
                    _ => unreachable!(),
                };

                let value: u32 = interposer
                    .get_cob(&COBCoord::new(row, col))
                    .unwrap()
                    .get_sw_register_group_value(from_dir, to_dir, group);
                format!(
                    "{} 32'h{} cob_{}_{}_sw_{}_{}\n",
                    format!("{:08x}", value),
                    address,
                    row,
                    col,
                    dir,
                    group
                )
            } else if let Some(captures) = COB_SEL_REGEX.captures(line) {
                let address = &captures[2];
                let row = captures[3].parse::<i64>().unwrap();
                let col = captures[4].parse::<i64>().unwrap();
                let dir = &captures[5];
                let group = captures[6].parse::<usize>().unwrap();

                let cob_dir = <COBDirection as FromStr>::from_str(dir)?;

                let value: u32 = interposer
                    .get_cob(&COBCoord::new(row, col))
                    .unwrap()
                    .get_sel_register_group_value(cob_dir, group);

                format!(
                    "{} 32'h{} cob_{}_{}_{}_sel_{}\n",
                    format!("{:08x}", value),
                    address,
                    row,
                    col,
                    dir,
                    group
                )
            } else {
                format!("{}\n", line)
            };

            outfile.write_all(new_line.as_bytes())?;
        }
    }

    Ok(())
}
